#include "stdafx.h"
#include "CmdMgr.h"
#include "InstantCmd.h"
#include "InteractiveCmd.h"
#include "CmdDef.h"
#include "../Env/EnvMgr.h"
#include "../Env/Environment.h"

using namespace Base::CmdFwk;

CmdMgr::CmdMgr()
    : m_activeCmd(0)
{
}

CmdMgr::~CmdMgr()
{
    // Delete the active command.
    if (m_activeCmd)
        deactivateCmd();
    else
        assert(false);

    // Clear all command definitions.
    for (CmdDefs::iterator it = m_cmdDefs.begin();
         it != m_cmdDefs.end(); ++it)
    {
        delete it->second;
        it->second = 0;
    }

    m_cmdDefs.clear();
}

CmdMgr*
CmdMgr::get()
{
    static CmdMgr theInstance;
    return &theInstance;
}

InteractiveCmd*
CmdMgr::activeCmd() const
{
    return m_activeCmd;
}

void
CmdMgr::doCmd(const void* cmdId)
{
    CmdDefs::const_iterator it = m_cmdDefs.find(cmdId);
    if (it != m_cmdDefs.end())
    {
        doCmd(it->second->createCmd());
    }
    else
        assert(false);
}

void
CmdMgr::doCmd(Command* cmd)
{
    if (cmd)
    {
        if (cmd->isInstantCmd())
        {
            InstantCmd* theCmd = static_cast<InstantCmd*>(cmd);
            theCmd->execute();
            
            delete theCmd;
            theCmd = 0;
        }
        else if (cmd->isInteractiveCmd())
        {
            InteractiveCmd* theCmd = static_cast<InteractiveCmd*>(cmd);

            if (m_activeCmd != theCmd)
            {
                // Update the active command.
                deactivateCmd();
                activateCmd(theCmd);                 
                
                // Update the command of the active envrionment.
                using namespace Base::Env;
                if (Environment* activeEnv = EnvMgr::get()->activeEnv())
                {
                    assert(m_cmdDefs.find(cmd->id()) != m_cmdDefs.end());
                    if (m_cmdDefs[cmd->id()]->isInEnv(activeEnv->id()))
                    {
                        activeEnv->cmd(cmd->id());
                    }
                }
                else
                    assert(m_cmdDefs[cmd->id()]->environments().empty());
            }
        }
        else
            assert(false);
    }
    else
        assert(false);
}

void
CmdMgr::deactivateCmd() 
{
    if (m_activeCmd)
    {
        if (m_activeCmd->state() == InteractiveCmd::eActive)
        {
            m_activeCmd->state(InteractiveCmd::eNormal);
        
            delete m_activeCmd;
            m_activeCmd = 0;
        }
        else
            assert(false);
    }
}

void
CmdMgr::activateCmd(InteractiveCmd* cmd)
{
    if (!m_activeCmd)
    {
        if (cmd->state() == InteractiveCmd::eNormal)
        {
            m_activeCmd = cmd;
            m_activeCmd->state(InteractiveCmd::eActive);
        }
        else
            assert(false);
    }
    else
        assert(false);
}

void
CmdMgr::addCmdDef(Base::CmdFwk::CmdDef *cmdDef)
{
    if (cmdDef)
    {
        CmdDefs::const_iterator it = m_cmdDefs.find(cmdDef->id());
        if (it == m_cmdDefs.end())
        {
            m_cmdDefs[cmdDef->id()] = cmdDef;
        }
        else
            assert(false);
    }
    else
        assert(false);
}

const CmdDef*
CmdMgr::cmdDef(const void* cmdId) const
{
    if (cmdId)
    {
        CmdDefs::const_iterator it = m_cmdDefs.find(cmdId);
        if (it != m_cmdDefs.end())
            return it->second;
    }
    else
        assert(false);

    return 0;
}

const std::vector<const CmdDef*>
CmdMgr::commandsIn(const void* envId)
{
    std::vector<const CmdDef*> result;

    for (CmdDefs::const_iterator it = m_cmdDefs.begin();
         it != m_cmdDefs.end(); ++it)
    {
        const CmdDef* cmdDef = it->second;
        if (cmdDef->isInEnv(envId))
            result.push_back(cmdDef);
    }

    return result;
}